/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "Controller.h"
//#define _DEBUG_


Controller::Controller()
{
  // Connect signals.
  mainwindow.signal_button_add_clicked.connect(
    sigc::mem_fun(*this, &Controller::on_dialog_main_button_add_clicked));
  mainwindow.signal_button_delete_clicked.connect(
    sigc::mem_fun(*this, &Controller::on_dialog_main_button_delete_clicked));
  mainwindow.signal_button_details_clicked.connect(
    sigc::mem_fun(*this, &Controller::on_dialog_main_button_details_clicked));
  mainwindow.booklist.signal_book_selected.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_main_gtkbooklist_signal_book_selected));
  mainwindow.booklist.signal_book_activated.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_main_gtkbooklist_signal_book_activated));
  diskstorage.signal_book_loaded.connect(
    sigc::mem_fun(*this, &Controller::on_diskstorage_signal_book_loaded));
  
  // Initialize the storage and load all books from the local HD.
  if (diskstorage.init(DEFAULT_BOOK_DIRECTORY) != 0) {
    char   primary[2000];
    char   secondary[2000];
    string directory = DEFAULT_BOOK_DIRECTORY;
    snprintf(primary, 2000, _("Unable to create or access the book folder"));
    snprintf(secondary,
             2000,
             _("The folder containing the book documents could not be "
               "created.\n"
               "This usually happens due "
               "to a problem with the file access restrictions given to this "
               "program by the administrator.\n"
               "Please make sure that the program has all permissions on "
               "\"%s\" and try again. Sorry."),
             directory.c_str());
    new DialogError(primary, secondary, mainwindow);
  }
  if (diskstorage.load_all() != 0) {
    char   primary[2000];
    char   secondary[2000];
    string directory = DEFAULT_BOOK_DIRECTORY;
    snprintf(primary, 2000, _("Unable to open the book folder"));
    snprintf(secondary,
             2000,
             _("The folder containing the book documents could not be opened.\n"
               "This usually happens due "
               "to a problem with the file access restrictions given to this "
               "program by the administrator.\n"
               "Please make sure that the program has all permissions on "
               "\"%s\" and try again. Sorry."),
             directory.c_str());
    new DialogError(primary, secondary, mainwindow);
  }
  
  // Initial preview text.
  Book book;
  char text[200];
  snprintf(text, 199, _("Welcome to %s"), "BibShelf");
  book.set_title(text);
  snprintf(text, 199, _("Version %s"), VERSION);
  book.set_author(text);
  book.set_summary(_("To view a book, please select an item from the "
                     "booklist."));
  book.set_category("");
  mainwindow.update_preview(&book);
}


Controller::~Controller()
{
}

void Controller::on_dialog_main_button_add_clicked(void)
{
  Book*             book   = new Book;
  DialogBookEditor* editor = new DialogBookEditor(book);
  bookeditorlist[book] = editor;
  editor->signal_button_cancel_clicked.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_bookeditor_signal_button_cancel_clicked));
  editor->signal_button_save_clicked.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_bookeditor_signal_button_save_clicked));
}


void Controller::on_dialog_main_button_delete_clicked(void)
{
  Book* book = mainwindow.booklist.get_first_selected();
  if (!book)
    return;
  DialogBookDelete* dialog = new DialogBookDelete(book, mainwindow);
  dialog->signal_button_cancel_clicked.connect(
               sigc::mem_fun(*this, &Controller::on_dialog_any_cancel_clicked));
  dialog->signal_button_delete_clicked.connect(
    sigc::mem_fun(*this,
                  &Controller::on_dialog_book_delete_button_delete_clicked));
}


void Controller::on_dialog_main_button_details_clicked(void)
{
  Book* book = mainwindow.booklist.get_first_selected();
  if (!book)
    return;
  on_dialog_main_gtkbooklist_signal_book_activated(book);
}


void Controller::on_dialog_book_delete_button_delete_clicked(
                                                          Gtk::Dialog* dialog,
                                                          Book* book)
{
  // If the deleted book has an editor window open, close it.
  if (bookeditorlist.find(book) != bookeditorlist.end()) {
    delete bookeditorlist.find(book)->second->get_book();
    delete bookeditorlist.find(book)->second;
    bookeditorlist.erase(book);
  }
  
  delete dialog;
  
  if (diskstorage.delete_book(book) != 0) {
    char   primary[2000];
    char   secondary[2000];
    string directory = DEFAULT_BOOK_DIRECTORY;
    snprintf(primary, 2000, _("Unable to delete the book \"%s\" by \"%s\""),
                         book->get_title().c_str(), book->get_author().c_str());
    snprintf(secondary,
             2000,
             _("The document containing the book that you have been trying to "
               "remove could not be deleted.\n\n"
               "This usually happens due "
               "to a problem with the file access restrictions given to this "
               "program by the administrator.\n"
               "Please make sure that the program has all permissions on "
               "\"%s\" and try again. Sorry."),
             directory.c_str());
    new DialogError(primary, secondary, mainwindow);
    return;
  }
  
  mainwindow.booklist.remove_book(book);
  delete book;
}


void Controller::on_dialog_any_cancel_clicked(Gtk::Dialog* dialog)
{
  delete dialog;
}


void Controller::on_diskstorage_signal_book_loaded(Book* book)
{
#ifdef _DEBUG_
  printf("Controller::on_diskstorage_signal_book_loaded(): Called.\n");
#endif
  mainwindow.booklist.insert_book(book);
}


void Controller::on_dialog_main_gtkbooklist_signal_book_selected(Book* book)
{
  mainwindow.update_preview(book);
}


void Controller::on_dialog_main_gtkbooklist_signal_book_activated(Book* book)
{
#ifdef _DEBUG_
  printf("Controller::on_dialog_main_gtkbooklist_signal_book_activated().\n");
#endif
  if (bookeditorlist.find(book) != bookeditorlist.end())
    return;
  Book* book_copy = new Book(*book);
  DialogBookEditor* editor = new DialogBookEditor(book_copy);
  bookeditorlist[book] = editor;
  editor->signal_button_cancel_clicked.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_bookeditor_signal_button_cancel_clicked));
  editor->signal_button_save_clicked.connect(
    sigc::mem_fun(*this,
      &Controller::on_dialog_bookeditor_signal_button_save_clicked));
}


void Controller::on_dialog_bookeditor_signal_button_cancel_clicked(
                                           DialogBookEditor* editor, Book* book)
{
#ifdef _DEBUG_
  printf("Controller::on_dialog_bookeditor_signal_button_cancel_clicked().\n");
#endif
  bookeditorlist.erase(book->get_originator());
  delete editor;
  delete book;
}


void Controller::on_dialog_bookeditor_signal_button_save_clicked(
                                           DialogBookEditor* editor, Book* book)
{
#ifdef _DEBUG_
  printf("Controller::on_dialog_bookeditor_signal_button_cancel_clicked().\n");
#endif
  int err = diskstorage.save_book(book);
  if (err != 0) {
    char   primary[2000];
    char   secondary[2000];
    string directory = DEFAULT_BOOK_DIRECTORY;
    
    // Display an error dialog.
    switch (err) {
    case STORAGE_ERROR_MAKEDIR_FAILED:
      snprintf(primary, 2000, _("Unable to create a folder for \"%s\""),
                              book->get_author().c_str());
      snprintf(secondary,
               2000,
               _("One possible cause for this problem may be that this program "
                 "has insufficient rights to create a new folder at the given "
                 "location.\n\n"
                 "Please make sure that the program has the permissions to "
                 "write into \"%s\" and try again. Sorry."),
               directory.c_str());
      break;
    
    case STORAGE_ERROR_FILE_DELETE_FAILED:
      snprintf(primary, 2000, _("Unable to delete old book information"));
      snprintf(secondary,
               2000,
               _("You have changed the author or the title of a book.\n"
                 "Thus, the document holding the old name and author need to "
                 "be deleted from your harddisk.\n"
                 "However, the deletion of this document failed, probably due "
                 "to a problem with the file access restrictions given to this "
                 "program by the administrator.\n"
                 "Please make sure that the program has all permissions on "
                 "\"%s\" and try again. Sorry."),
               directory.c_str());
      break;
    
    default:
      snprintf(primary, 2000, _("Unable to save the book \"%s\" by \"%s\""),
               book->get_title().c_str(), book->get_author().c_str());
      snprintf(secondary,
               2000,
               _("One possible cause for this problem may be that this program "
                 "has insufficient rights to create a new file at the given "
                 "location.\n\n"
                 "Please make sure that the program has the permissions "
                 "to write into all folders below \"%s\" and try again. "
                 "Sorry."),
               directory.c_str());
      break;
    }
    new DialogError(primary, secondary, *editor);
    return;
  }
  
  *book->get_originator() = *book;
  bookeditorlist.erase(book->get_originator());
  
  // If this is a new book, insert it into the booklist and return.
  if (book->get_originator() == book) {
    mainwindow.booklist.insert_book(book);
    delete editor;
    return;
  }
  
  // Update the filelist, and if necessary, the preview.
  mainwindow.booklist.update_soft();
  if (mainwindow.booklist.get_first_selected() == book->get_originator())
    mainwindow.update_preview(book->get_originator());
  
  delete editor;
  delete book;
}
